package com.nagornyi.uc;

import com.google.appengine.labs.repackaged.org.json.JSONException;
import com.google.appengine.labs.repackaged.org.json.JSONObject;
import com.nagornyi.uc.common.captcha.http.HttpLoader;
import com.nagornyi.uc.common.captcha.http.SimpleHttpLoader;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.StringReader;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Nagornyi
 * Date: 08.06.14
 */
public class AppInfoLoader {
    private static Logger log = Logger.getLogger(AppInfoLoader.class.getName());

    private static String GOOGLE_CURRENCY_URL = "http://rate-exchange.appspot.com/currency?from=EUR&to=UAH";
    private static String PRIVATE_BANK_CURRENCY_URL = "https://api.privatbank.ua/p24api/pubinfo?exchange&coursid=3";
    private static long updateInterval = 6*60*60*1000; // every 6 hours TODO make it config

    private boolean isLoading = false;
    private boolean initialized = false;
    private Long lastUpdate = new Date().getTime();
    AppInfo appInfo = new AppInfo();

    private HttpLoader httpLoader = new SimpleHttpLoader();

    private void loadInfo() throws JSONException {
        isLoading = true;
        log.info("Updating App Info");

        try {
            String response = httpLoader.httpGet(PRIVATE_BANK_CURRENCY_URL);

            if (response != null) {
                boolean found = parseXML(response);
                if (!found) {
                    String googleResp = httpLoader.httpGet(GOOGLE_CURRENCY_URL);  //{"to": "UAH", "rate": 16.1401, "from": "EUR"}
                    if (googleResp != null) {
                        JSONObject object = new JSONObject();
                        appInfo.setCurrencyRate(object.getDouble("rate"));
                    }
                    else {
                        log.info("Couldn't load currency rates from google");
                    }
                }
            } else {
                log.info("Couldn't load currency rates from privat ");
            }
            lastUpdate = new Date().getTime();
        } finally {
            isLoading = false;
        }

    }

    public void run() {
        if ((new Date().getTime() > lastUpdate + updateInterval && !isLoading) || !initialized) {
            try {
                loadInfo();
            } catch (JSONException e) {
                log.log(Level.WARNING, "Couldn't load app info");
            }
            initialized = true;
        }
    }

    private static final AppInfoLoader INSTANCE = new AppInfoLoader();

    public static AppInfoLoader getInstance() {
        return INSTANCE;
    }

    public double getCurrencyRate() {
        return appInfo.getCurrencyRate();
    }

    private boolean parseXML(String xml) {
        boolean found = false;
        try {
            log.info("rates response : " + xml);

            SAXParserFactory factory = SAXParserFactory.newInstance();
            SAXParser parser = factory.newSAXParser();
            StringReader reader = new StringReader(xml.trim());

            CRHandler handler = new CRHandler();
            parser.parse(new InputSource(reader), handler);
            found = handler.isFound();
        } catch (Exception e) {
            log.log(Level.WARNING, "can't parse rates xml", e);
        }
        return found;
    }

    class CRHandler extends DefaultHandler {

        private boolean found;

        public void startElement(String uri, String localName, String qName,
                                 Attributes attributes) throws SAXException {

            if ("exchangerate".equals(qName) && "EUR".equals(attributes.getValue("ccy"))) {
                appInfo.setCurrencyRate(Double.parseDouble(attributes.getValue("buy")));
                found = true;
            }
        }

        boolean isFound() {
            return found;
        }
    }
}
